package k8s

import (
	"bytes"
	"context"
	"errors"
	"fmt"

	"gitee.com/hexug/go-tools/logger"
	appsv1 "k8s.io/api/apps/v1"
	corev1 "k8s.io/api/core/v1"
	k8serr "k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/util/yaml"
)

// 解析YAML字符串为Deployment对象
func parseYAMLToDeployment(yamlStr string) (*appsv1.Deployment, error) {
	reader := bytes.NewReader([]byte(yamlStr))
	decoder := yaml.NewYAMLOrJSONDecoder(reader, 4096)

	deployment := &appsv1.Deployment{}
	if err := decoder.Decode(deployment); err != nil {
		return nil, fmt.Errorf("YAML格式错误: %v", err)
	}

	// 验证核心字段
	if deployment.Kind != "Deployment" {
		logger.L().Errorf("YAML中定义的资源类型不是Deployment")
		return nil, errors.New("YAML中定义的资源类型不是Deployment")
	}
	if deployment.APIVersion != "apps/v1" {
		logger.L().Errorf("Deployment的apiVersion必须为apps/v1")
		return nil, errors.New("Deployment的apiVersion必须为apps/v1")
	}
	if deployment.Name == "" {
		logger.L().Errorf("Deployment名称不能为空")
		return nil, errors.New("Deployment名称不能为空")
	}
	if deployment.Spec.Selector == nil {
		logger.L().Errorf("必须指定spec.selector")
		return nil, errors.New("必须指定spec.selector")
	}
	if len(deployment.Spec.Template.Spec.Containers) == 0 {
		logger.L().Errorf("必须定义至少一个容器")
		return nil, errors.New("至少需要定义一个容器")
	}

	return deployment, nil
}

// 处理创建过程中的错误
func handleCreateError(c context.Context, deployment *appsv1.Deployment, err error) (*appsv1.Deployment, error) {
	// 使用client-go的errors包判断错误类型
	switch {
	case k8serr.IsAlreadyExists(err): // 正确判断资源已存在错误
		logger.L().Errorf("Deployment %s/%s 已存在", deployment.Namespace, deployment.Name)
		return nil, fmt.Errorf("Deployment %s/%s 已存在", deployment.Namespace, deployment.Name)
	case k8serr.IsForbidden(err): // 权限不足错误
		logger.L().Errorf("权限不足，无法创建Deployment: %v", err)
		return nil, fmt.Errorf("权限不足，无法创建Deployment: %v", err)
	case k8serr.IsTimeout(err): // 超时错误
		logger.L().Errorf("创建超时: %v", err)
		return nil, fmt.Errorf("创建超时: %v", err)
	case k8serr.IsNotFound(err): // 命名空间不存在等情况
		logger.L().Errorf("资源不存在: %v", err)
		return nil, fmt.Errorf("资源不存在: %v", err)
	default:
		logger.L().Errorf("创建失败: %v", err)
		return nil, fmt.Errorf("创建失败: %v", err)
	}
}

// 解析YAML字符串为Pod对象
func parseYAMLToPod(yamlStr string) (*corev1.Pod, error) {
	// 检查YAML字符串是否为空
	if yamlStr == "" {
		return nil, errors.New("YAML字符串不能为空")
	}

	reader := bytes.NewReader([]byte(yamlStr))
	decoder := yaml.NewYAMLOrJSONDecoder(reader, 4096)

	pod := &corev1.Pod{}
	if err := decoder.Decode(pod); err != nil {
		// 这里可以添加更详细的错误信息
		return nil, fmt.Errorf("YAML格式错误: %v, 原始内容: %s", err, yamlStr)
	}

	// 验证核心字段
	if pod.Kind != "Pod" {
		errMsg := fmt.Sprintf("YAML中定义的资源类型不是Pod，实际是: %s", pod.Kind)
		logger.L().Errorf(errMsg)
		return nil, errors.New(errMsg)
	}
	if pod.APIVersion != "v1" {
		errMsg := fmt.Sprintf("Pod的apiVersion必须为v1，实际是: %s", pod.APIVersion)
		logger.L().Errorf(errMsg)
		return nil, errors.New(errMsg)
	}
	if pod.Name == "" {
		logger.L().Errorf("Pod名称不能为空")
		return nil, errors.New("Pod名称不能为空")
	}
	if len(pod.Spec.Containers) == 0 {
		logger.L().Errorf("必须定义至少一个容器")
		return nil, errors.New("至少需要定义一个容器")
	}

	// 检查容器是否有名称和镜像
	for i, container := range pod.Spec.Containers {
		if container.Name == "" {
			errMsg := fmt.Sprintf("第%d个容器名称不能为空", i+1)
			logger.L().Errorf(errMsg)
			return nil, errors.New(errMsg)
		}
		if container.Image == "" {
			errMsg := fmt.Sprintf("第%d个容器镜像不能为空", i+1)
			logger.L().Errorf(errMsg)
			return nil, errors.New(errMsg)
		}
	}

	return pod, nil
}

// 处理创建过程中的错误
func handleCreatePodError(c context.Context, pod *corev1.Pod, err error) (*corev1.Pod, error) {
	// 使用client-go的errors包判断错误类型
	switch {
	case k8serr.IsAlreadyExists(err): // 正确判断资源已存在错误
		logger.L().Errorf("Pod %s/%s 已存在", pod.Namespace, pod.Name)
		return nil, fmt.Errorf("Pod %s/%s 已存在", pod.Namespace, pod.Name)
	case k8serr.IsForbidden(err): // 权限不足错误
		logger.L().Errorf("权限不足，无法创建Pod: %v", err)
		return nil, fmt.Errorf("权限不足，无法创建Pod: %v", err)
	case k8serr.IsTimeout(err): // 超时错误
		logger.L().Errorf("创建超时: %v", err)
		return nil, fmt.Errorf("创建超时: %v", err)
	case k8serr.IsNotFound(err): // 命名空间不存在等情况
		logger.L().Errorf("资源不存在: %v", err)
		return nil, fmt.Errorf("资源不存在: %v", err)
	default:
		logger.L().Errorf("创建失败: %v", err)
		return nil, fmt.Errorf("创建失败: %v", err)
	}
}
